Skip to main content

Date and time

In This Section

This article includes several examples that use the date_time type:

This section contains topics for many common uses of the date_time struct:

The xtd::date_time value type represents dates and times with values ranging from 00:00:00 (midnight), January 1, 0001 Anno Domini (Common Era) through 11:59:59 P.M., December 31, 9999 A.D. (C.E.) in the Gregorian calendar.

Time values are measured in 100-nanosecond units called ticks. A particular date is the number of ticks since 12:00 midnight, January 1, 0001 A.D. (C.E.) in the GregorianCalendar calendar. The number excludes ticks that would be added by leap seconds. For example, a ticks value of 31241376000000000L represents the date Friday, January 01, 0100 12:00:00 midnight. A xtd::date_time value is always expressed in the context of an explicit or default calendar.

Note

If you are working with a ticks value that you want to convert to some other time interval, such as minutes or seconds, you should use the time_span::ticks_per_day, time_span::ticks_per_hour, time_span::ticks_per_minute, time_span::ticks_per_second, time_span::ticks_per_millisecond , or time_span::ticks_per_microsecond constant to perform the conversion. For example, to add the number of seconds represented by a specified number of ticks to the second component of a xtd::date_time value, you can use the expression

date_value.second() + n_ticks / time_span::ticks_per_second.

You can view the source for the entire set of examples from this article from the examples repository on GitHub.

Initializing a date_time object

You can assign an initial value to a new date_time value in many different ways:

  • Calling a constructor, either one where you specify arguments for values, or use the implicit parameterless constructor.
  • Assigning a date_time to the return value of a property or method.
  • Parsing a date_time value from its string representation.

The following code snippets show examples of each:

Invoke constructors

You call any of the overloads of the date_time constructor that specify elements of the date and time value (such as the year, month, and day, or the number of ticks). The following code creates a specific date using the date_time constructor specifying the year, month, day, hour, minute, and second.

auto date1 = date_time {2008, 5, 1, 8, 30, 52};
console::write_line(date1);

You invoke the date_time structure's implicit parameterless constructor when you want a date_time initialized to its default value. The following example illustrates the date_time implicit parameterless constructor.

auto dat1 = date_time {};
// The following method call displays 1/1/0001 12:00:00 AM.
console::write_line(dat1.to_string());
// The following method call displays true.
console::write_line(dat1 == date_time::min_value);

Assigning a computed value

You can assign the date_time object a date and time value returned by a property or method. The following example assigns the current date and time, the current Coordinated Universal Time (UTC) date and time, and the current date to three new date_time variables.

date_time date1 = date_time::now();
date_time date2 = date_time::utc_now();
date_time date3 = date_time.today();

Parsing a string that represents a date_time

The xtd::date_time::parse, and xtd::date_time::try_parse methods all convert a string to its equivalent date and time value. The following examples use the xtd::date_time::parse method to parse a string and convert it to a date_time value. The second format uses a form supported by the ISO 8601 standard for a representing date and time in string format. This standard representation is often used to transfer date information in web services.

auto date_string = "5/1/2008 8:30:52 AM";
date_time date1 = date_time::parse(date_string, std::locale());
auto iso8601_string = "20080501T08:30:52Z";
date_time date_iso8602 = date_time::parse_exact(iso8601_string, "yyyyMMddTHH:mm:ssZ", std::locale());

The try_parse method indicates whether a string is a valid representation of a date_time value and, if it is, performs the conversion.

date_time values and their string representations

Internally, all date_time values are represented as the number of ticks (the number of 100-nanosecond intervals) that have elapsed since 12:00:00 midnight, January 1, 0001. The actual date_time value is independent of the way in which that value appears when displayed. The appearance of a date_time value is the result of a formatting operation that converts a value to its string representation.

The appearance of date and time values is dependent on culture, international standards, application requirements, and personal preference. The date_time structure offers flexibility in formatting date and time values through overloads of to_string. The default xtd::date_time::to_string method returns the string representation of a date and time value using the current culture's short date and long time pattern. The following example uses the default xtd::date_time::to_string method. It displays the date and time using the short date and long time pattern for the current culture. The en-US culture is the current culture on the computer on which the example was run.

auto date1 = date_time {2008, 3, 1, 7, 0, 0};
console::write_line(date1.to_string());
// For en-US culture, displays Sat Mar 1 07:00:00 2008

You may need to format dates in a specific culture to support web scenarios where the server may be in a different culture from the client. You specify the culture using the std::locale method to create the short date and long time representation in a specific culture. The following example uses the xtd::date_time::to_string method to display the date and time using the short date and long time pattern for the fr-FR culture.

auto date1 = date_time {2008, 3, 1, 7, 0, 0};
std::locale::global(std::locale("fr_FR.utf-8"));
console::write_line(date1.to_string());
// Displays Sam 1 mar 07:00:00 2008

Other applications may require different string representations of a date. The date_time::to_string method returns the string representation defined by a standard or custom format specifier using the formatting conventions of the current culture. The following example uses the date_rime::to_string method to display the full date and time pattern for the en-US culture, the current culture on the computer on which the example was run.

auto date1 = date_time {2008, 3, 1, 7, 0, 0};
console::write_line(date1.to_string("F"));
// Displays Sat Mar 1 07:00:00 2008

Finally, you can specify both the culture and the format using the std::locale method. The following example uses the date_rime::to_string method to display the full date and time pattern for the fr-FR culture.

auto date1 = date_time {2008, 3, 1, 7, 0, 0};
std::locale::global(std::locale("fr_FR.utf-8"));
console::write_line(date1.to_string("F"));
// Displays Sam 1 mar 07:00:00 2008

For more information about formatting date_time values, see Standard Date and Time Format Strings and Custom Date and Time Format Strings.

Parse date_time values from strings

Parsing converts the string representation of a date and time to a date_time value. Typically, date and time strings have two different usages in applications:

  • A date and time takes a variety of forms and reflects the conventions of either the current culture or a specific culture. For example, an application allows a user whose current culture is en-US to input a date value as "12/15/2013" or "December 15, 2013". It allows a user whose current culture is en-gb to input a date value as "15/12/2013" or "15 December 2013."
  • A date and time is represented in a predefined format. For example, an application serializes a date as "20130103" independently of the culture on which the app is running. An application may require dates be input in the current culture's short date format.

You use the parse or try_parse method to convert a string from one of the common date and time formats used by a culture to a date_time value. The following example shows how you can use try_parse to convert date strings in different culture-specific formats to a date_time value. It changes the current culture to English (United Kingdom) and calls the get_date_time_formats method to generate an array of date and time strings. It then passes each element in the array to the try_parse method. The output from the example shows the parsing method was able to successfully convert each of the culture-specific date and time strings.

  std::locale::global(std::locale("en_GB.utf-8"));

auto date1 = date_time {2013, 6, 1, 12, 32, 30};
auto bad_formats = vector<ustring> {};

console::write_line("{,-37} {,-19}\n", "Date String", "Date");
for (auto date_string : date1.get_date_time_formats()) {
auto parsed_date = date_time {};
if (date_time::try_parse(date_string, parsed_date))
console::write_line("{,-37} {,-19}", date_string, date_time::parse(date_string));
else
bad_formats.push_back(date_string);
}

// Display strings that could not be parsed.
if (bad_formats.size() > 0_sz) {
console::write_line("\nStrings that could not be parsed: ");
for (auto bad_format : bad_formats)
console::write_line(bad_format);
}
// Press "Run" to see the output.}

date_time values

Descriptions of time values in the date_time type are often expressed using the Coordinated Universal Time (UTC) standard. Coordinated Universal Time is the internationally recognized name for Greenwich Mean Time (GMT). Coordinated Universal Time is the time as measured at zero degrees longitude, the UTC origin point. Daylight saving time is not applicable to UTC.

Local time is relative to a particular time zone. A time zone is associated with a time zone offset. A time zone offset is the displacement of the time zone measured in hours from the UTC origin point. In addition, local time is optionally affected by daylight saving time, which adds or subtracts a time interval adjustment. Local time is calculated by adding the time zone offset to UTC and adjusting for daylight saving time if necessary. The time zone offset at the UTC origin point is zero.

UTC time is suitable for calculations, comparisons, and storing dates and time in files. Local time is appropriate for display in user interfaces of desktop applications. Time zone-aware applications (such as many Web applications) also need to work with a number of other time zones.

If the kind property of a date_time object is date_time_kind::unspecified, it is unspecified whether the time represented is local time, UTC time, or a time in some other time zone.

date_time operations

A calculation using a date_time structure, such as add or subtract, does not modify the value of the structure. Instead, the calculation returns a new date_time structure whose value is the result of the calculation. Conversion operations between time zones (such as between UTC and local time, or between one time zone and another) take daylight saving time into account, but arithmetic and comparison operations do not.

The date_time structure itself offers limited support for converting from one time zone to another. You can use the to_local_time method to convert UTC to local time, or you can use the to_universal_time method to convert from local time to UTC. However, a full set of time zone conversion methods is available in the time_zone_info class. You convert the time in any one of the world's time zones to the time in any other time zone using these methods.

Calculations and comparisons of date_time objects are meaningful only if the objects represent times in the same time zone. You can use a time_zone_info object to represent a date_time value's time zone, although the two are loosely coupled. A date_time object does not have a property that returns an object that represents that date and time value's time zone. The kind property indicates if a date_time represents UTC, local time, or is unspecified. In a time zone-aware application, you must rely on some external mechanism to determine the time zone in which a date_time object was created. You could use a structure that wraps both the date_time value and the time_zone_info object that represents the date_time value's time zone. For details on using UTC in calculations and comparisons with date_time values, see Performing Arithmetic Operations with Dates and Times.

Each date_time member implicitly uses the Gregorian calendar to perform its operation. Exceptions are methods that implicitly specify a calendar.

Operations by members of the date_time type take into account details such as leap years and the number of days in a month.

date_time vs. time_span

The date_time and time_span value types differ in that a date_time represents an instant in time whereas a time_span represents a time interval. You can subtract one instance of date_time from another to obtain a time_span object that represents the time interval between them. Or you could add a positive time_span to the current date_time to obtain a date_time value that represents a future date. You can add or subtract a time interval from a date_time object. Time intervals can be negative or positive, and they can be expressed in units such as ticks, seconds, or as a time_span object.

Compare for equality within tolerance

Equality comparisons for date_time values are exact. That means two values must be expressed as the same number of ticks to be considered equal. That precision is often unnecessary or even incorrect for many applications. Often, you want to test if date_time objects are roughly equal. The following example demonstrates how to compare roughly equivalent date_time values. It accepts a small margin of difference when declaring them equal.

static bool roughly_equals(const date_time& time, const date_time& time_with_window, int window_in_seconds, int frequency_in_seconds) {
auto delta = convert::to_int32((time_with_window - time).total_seconds_duration().count()) % frequency_in_seconds;
delta = delta > window_in_seconds ? frequency_in_seconds - delta : delta;
return math::abs(delta) < window_in_seconds;
}

static void test_roughly_equals() {
auto window = 10;
auto freq = 60 * 60 * 2; // 2 hours;

auto d1 = date_time::now();

auto d2 = d1.add_seconds(2 * window);
auto d3 = d1.add_seconds(-2 * window);
auto d4 = d1.add_seconds(window / 2);
auto d5 = d1.add_seconds(-window / 2);

auto d6 = (d1.add_hours(2)).add_seconds(2 * window);
auto d7 = (d1.add_hours(2)).add_seconds(-2 * window);
auto d8 = (d1.add_hours(2)).add_seconds(window / 2);
auto d9 = (d1.add_hours(2)).add_seconds(-window / 2);

console::write_line("d1 ({0}) ~= d1 ({1}): {2}", d1, d1, roughly_equals(d1, d1, window, freq));
console::write_line("d1 ({0}) ~= d2 ({1}): {2}", d1, d2, roughly_equals(d1, d2, window, freq));
console::write_line("d1 ({0}) ~= d3 ({1}): {2}", d1, d3, roughly_equals(d1, d3, window, freq));
console::write_line("d1 ({0}) ~= d4 ({1}): {2}", d1, d4, roughly_equals(d1, d4, window, freq));
console::write_line("d1 ({0}) ~= d5 ({1}): {2}", d1, d5, roughly_equals(d1, d5, window, freq));

console::write_line("d1 ({0}) ~= d6 ({1}): {2}", d1, d6, roughly_equals(d1, d6, window, freq));
console::write_line("d1 ({0}) ~= d7 ({1}): {2}", d1, d7, roughly_equals(d1, d7, window, freq));
console::write_line("d1 ({0}) ~= d8 ({1}): {2}", d1, d8, roughly_equals(d1, d8, window, freq));
console::write_line("d1 ({0}) ~= d9 ({1}): {2}", d1, d9, roughly_equals(d1, d9, window, freq));
}

// The example displays output similar to the following:
// d1 (Thu Dec 30 16:18:10 2021) ~= d1 (Thu Dec 30 16:18:10 2021): true
// d1 (Thu Dec 30 16:18:10 2021) ~= d2 (Thu Dec 30 16:18:30 2021): false
// d1 (Thu Dec 30 16:18:10 2021) ~= d3 (Thu Dec 30 16:17:50 2021): false
// d1 (Thu Dec 30 16:18:10 2021) ~= d4 (Thu Dec 30 16:18:15 2021): true
// d1 (Thu Dec 30 16:18:10 2021) ~= d5 (Thu Dec 30 16:18:05 2021): true
// d1 (Thu Dec 30 16:18:10 2021) ~= d6 (Thu Dec 30 18:18:30 2021): false
// d1 (Thu Dec 30 16:18:10 2021) ~= d7 (Thu Dec 30 18:17:50 2021): false
// d1 (Thu Dec 30 16:18:10 2021) ~= d8 (Thu Dec 30 18:18:15 2021): true
// d1 (Thu Dec 30 16:18:10 2021) ~= d9 (Thu Dec 30 18:18:05 2021): true

See also